package com.swak.paxos.impl;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import com.swak.paxos.Learner;
import com.swak.paxos.PaxosConfig;

/**
 * AutomaticLearner.
 * 
 * @author 618lf
 */
@SuppressWarnings("unused")
public abstract class AutomaticLearner implements Learner {

	private final PaxosConfig config;
	private volatile boolean isIMSending;
	private volatile long absLastSendTime;
	private volatile boolean isComfirmed;
	private volatile long beginInstanceID;
	private volatile String learnerNodeID;
	private volatile boolean isEnd;
	private volatile boolean isStart;
	
	private volatile String sendToNodeID;
	private volatile long ackInstanceID;
	private volatile long absLastAckTime;

	/**
	 * lock and condition
	 */
	private ReentrantLock lock = new ReentrantLock();
	private Condition condition = lock.newCondition();
	
	

	public AutomaticLearner(PaxosConfig config) {
		this.config = config;
	}

	/**
	 * 确认学习
	 */
	protected boolean comfirm(long beginInstanceID, String learnerNodeID) {
		this.lock.lock();
		try {
			boolean confirmRet = false;
			if (isIMSending() && !this.isComfirmed) {
				if (this.beginInstanceID == beginInstanceID && this.learnerNodeID.equals(learnerNodeID)) {
					confirmRet = true;
					this.isComfirmed = true;
					this.condition.notify();
				}
			}
			return confirmRet;
		} finally {
			this.lock.unlock();
		}
	}

	/**
	 * 判断是否在发送中，没有发送或者已经超时均算为未发送状态。
	 * @return
	 */
	protected boolean isIMSending() {
		if (!this.isIMSending) {
			return false;
		}

		long nowTime = System.currentTimeMillis();
		long passTime = nowTime > this.absLastSendTime ? nowTime - this.absLastSendTime : 0;
		if (passTime >= this.config.getLearnerSenderPrepareTimeoutMs()) {
			return false;
		}
		return true;
	}

	protected void waitToSend() {
		this.lock.lock();
		while (!this.isComfirmed) {
			try {
				this.condition.wait(1000);
			} catch (Exception e) {
			}
			if (this.isEnd)
				break;
		}
		this.lock.unlock();
	}
	
	protected void sendDone() {
		this.lock.lock();
		this.isIMSending = false;
		this.isComfirmed = false;
		this.beginInstanceID = (long) - 1;
		this.sendToNodeID = "";
		this.absLastSendTime = 0;
		this.ackInstanceID = 0;
		this.absLastAckTime = 0;
		this.lock.unlock();
	}
	
	private void runTask() {
		this.isStart = true;
		while (true) {
			try {
				waitToSend();

				if (this.isEnd) {
					return;
				}

				sendLearnedValue(beginInstanceID, sendToNodeID);
				sendDone();
			} catch (Exception e) {
			}
		}
	}
	
	protected void sendLearnedValue(long beginInstanceID, String sendToNodeID) {
		
	}
}